// $Id: lamp.c 297 2013-10-26 04:17:24Z alan.watson.f $

#define _POSIX_C_SOURCE 200112L

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <arpa/inet.h>
#include <netdb.h>

#include "oaxaca-config.h"
#include "oaxaca.h"

////////////////////////////////////////////////////////////////////////////////

int
oaxaca_lamp_initialized(void)
{
  return oaxaca_shm != NULL && oaxaca_shm->lamp.initialized;
}

char
oaxaca_lamp_command(void)
{
  if (oaxaca_shm == NULL)
    return 0;
  else
    return oaxaca_shm->lamp.command;
}

void
oaxaca_lamp_set_command(char command)
{
  if (oaxaca_shm != NULL)
    oaxaca_shm->lamp.command = command;
}

int
oaxaca_lamp_state(void)
{
  if (oaxaca_shm == NULL)
    return 0;
  else
    return oaxaca_shm->lamp.state;
}

////////////////////////////////////////////////////////////////////////////////

static FILE *out;
static FILE *in;

static void
server_open(const char *servername, int serverport, FILE **in, FILE **out)
{
  oaxaca_info("connecting to server %s:%d.", servername, serverport);

  int fd = socket(AF_INET, SOCK_STREAM, 0);
  if (fd < 0)
    oaxaca_error("socket failed.");
    
  struct sockaddr_in sa;
  memset(&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons(serverport);
  
  errno = 0;
  struct hostent *hostinfo = gethostbyname(servername);
  if (hostinfo == NULL)
    oaxaca_error("gethostbyname failed: %s.", strerror(errno));
  sa.sin_addr = * (struct in_addr *) hostinfo->h_addr_list[0];
    
  errno = 0;
  if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
    oaxaca_error("connect failed: %s.", strerror(errno));

  *in = fdopen(fd, "r");
  *out = fdopen(fd, "w");
  setvbuf(*out, NULL, _IOLBF, 0);

  oaxaca_info("connected.", servername, serverport);
}

////////////////////////////////////////////////////////////////////////////////

static void
switch_lamp(int state)
{
  oaxaca_info("switching lamp %s.", state ? "on" : "off");
  fprintf(out, "l %d\n", state);
  unsigned long u;
  if (fscanf(in, "%lu", &u) != 1)
    oaxaca_error("invalid reply from server.");
  oaxaca_info("finished switching lamp %s.", state ? "on" : "off");
}

////////////////////////////////////////////////////////////////////////////////

static void
atexitcallee(void)
{
  if (oaxaca_shm != NULL)
    oaxaca_shm->lamp.initialized = 0;
}

void
oaxaca_lamp_main(void)
{
  oaxaca_common_main("lamp");
  atexit(atexitcallee);
  
  oaxaca_info("initializing lamp hardware.");
  server_open("lamp", 5002, &in, &out);

  oaxaca_shm->lamp.initialized = 0;
  oaxaca_shm->lamp.command     = '0';
  oaxaca_shm->lamp.state       = 0;
//  switch_lamp(0);
  oaxaca_shm->lamp.command     = 'I';
  oaxaca_shm->lamp.initialized = 1;
    
  oaxaca_info("starting command loop.");

  for (;;) {
    int command = oaxaca_shm->lamp.command;
    switch (command) {
    case '0': // switch lamp off
      switch_lamp(0);
      oaxaca_shm->lamp.state = 0;
      oaxaca_shm->lamp.command = 'I';
      break;
   case '1': // switch lamp on
      switch_lamp(1);
      oaxaca_shm->lamp.state = 1;
      oaxaca_shm->lamp.command = 'I';      
      ;;
    case 'i': // start idling
      oaxaca_shm->lamp.command = 'I';
      break;
    case 'I': // continue idling
      break;
    default:
      oaxaca_error("unrecognized command \'%c\'.", command);
      break;
    }
    oaxaca_usleep(100000);
  }
  
  oaxaca_error("command loop terminated.");
}

////////////////////////////////////////////////////////////////////////////////